package fr.toto.subtitles;

import java.io.IOException;
import java.io.Serializable;
import java.nio.file.FileSystem;
import java.nio.file.FileSystems;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Arrays;
import java.util.Date;
import java.util.Set;

import com.kokotchy.betaSeriesAPI.HashCodeUtil;
import com.kokotchy.betaSeriesAPI.model.Episode;
import com.kokotchy.betaSeriesAPI.model.Subtitle;
import com.kokotchy.betaSeriesAPI.model.SubtitleLanguage;

import fr.toto.constantes.Constantes;
import fr.toto.exceptions.ProcessException;
import fr.toto.triseries.BetaSeriesQuery;
import fr.toto.triseries.EpisodesSet;
import fr.toto.triseries.Regex;
import fr.toto.triseries.Reglages;

public class Soutitre implements Serializable, Runnable {

	/**
	 * 
	 */
	private static final long serialVersionUID = 6033944077390241678L;
	private String url;
	private int season;
	private int episode;
	private SubtitleLanguage lang;
	private String file;
	private int nbtry;

	public Soutitre(Episode ep, SubtitleLanguage lang2, String file) {
		url = ep.getShowUrl();
		season = ep.getSeason();
		episode = ep.getEpisode();
		this.lang = lang2;
		this.file = file;
		nbtry = 0;
	}

	public Soutitre(String url, int season, int episode, SubtitleLanguage lang,
			String file) {
		this.url = url;
		this.season = season;
		this.episode = episode;
		this.lang = lang;
		this.file = file;
		nbtry = 0;
	}

	@Override
	public String toString() {
		return String.format("%s - %02dx%02d - %s", url, season, episode, lang);
	}

	@Override
	public int hashCode() {
		int result = HashCodeUtil.SEED;
		result = HashCodeUtil.hash(result, url);
		result = HashCodeUtil.hash(result, season);
		result = HashCodeUtil.hash(result, episode);
		result = HashCodeUtil.hash(result, lang);
		return result;
	}

	public boolean equals(Soutitre s) {
		return (this.url.equals(s.url)) && (this.season == s.season)
				&& (this.episode == s.episode) && (this.lang.equals(s.lang));

	}

	@Override
	public void run() {
		if(lang == SubtitleLanguage.UNKNOWN) {
			SoutitreSet.remove(this);
			SoutitreSet.Save();
			return;
		}
		
		nbtry++;
		if (Arrays.binarySearch(Constantes.trysearchsub, nbtry) >= 0) {
			if (Reglages.DEBUG)
				System.out.print(String.format(
						Constantes.DEBUGMSG.getString("startSearchSub"), url,
						season, episode, lang));

			Episode ep = EpisodesSet.find(url, season, episode);
			if (ep == null) {
				if (Reglages.DEBUG)
					System.out.print(Constantes.DEBUGMSG
							.getString("needMoreIntel"));
				ep = BetaSeriesQuery.getEpisode(url, season, episode);
				if (ep == null) {
					SoutitreSet.add(this);
					SoutitreSet.Save();
					return;
				}
				EpisodesSet.add(ep);
			}
			getSubtitle(ep);
		}
	}

	public void getSubtitle(Episode ep) {
		try {
			// récupération liste de soustitres
			Set<Subtitle> subs = ep.getSubtitles();
			if (subs == null || subs.isEmpty()) {
				Long l = (new Date().getTime()) / 1000 - ep.getDate();
				if (l > 16200000) {
					subs = BetaSeriesQuery.getSubtitle(url, season, episode,
							lang);
				} else {
					if (Reglages.DEBUG)
						System.out.print(Constantes.DEBUGMSG
								.getString("noSubAvailable"));
					SoutitreSet.add(this);
					return;
				}
			}

			// Sélection du soustitre
			if (Reglages.DEBUG)
				System.out.print(Constantes.DEBUGMSG.getString("selectSub"));
			Subtitle sub = Regex.getBestSubtitle(subs, file, lang, episode,
					season);
			if (sub == null) {
				if (Reglages.DEBUG)
					System.out.print(Constantes.DEBUGMSG
							.getString("noSubAvailable"));
				SoutitreSet.add(this);
				return;
			}

			if (sub.getContent().iterator().next() == null) {
				// traitement pour un fichier soustitre non zippé
				if (Reglages.DEBUG)
					System.out.print(String.format(
							Constantes.DEBUGMSG.getString("selectedSub"),
							sub.getFile()));

				String ext = sub.getFile().substring(
						sub.getFile().lastIndexOf("."), sub.getFile().length());

				Path subfile = Paths.get(Regex.getEpisodeDest(ep).toString()
						+ "." + lang + ext);

				if (Files.exists(subfile)) {
					if (Reglages.DEBUG)
						System.out
								.print(Constantes.DEBUGMSG
										.getString("searchfailed")
										+ Constantes.DEBUGMSG
												.getString("destSubExist"));
					SoutitreSet.remove(this);
					return;
				}

				Download.downloadfile(sub.getUrl(), subfile.toString());

				if (Reglages.DEBUG)
					System.out.print(Constantes.DEBUGMSG
							.getString("searchComplete")
							+ String.format(
									Constantes.DEBUGMSG.getString("subAdded"),
									subfile.toString()));
			} else {
				// traitement pour un soustitre contenu dans un ZIP
				if (Reglages.DEBUG)
					System.out.print(String.format(
							Constantes.DEBUGMSG.getString("selectedSub"), sub
									.getContent().iterator().next()));

				String subInZip = sub.getContent().iterator().next();

				Path zipfile = Paths.get(Regex.getEpisodeDest(ep).getParent()
						.toString(), sub.getFile().replaceAll(Regex.BADCHARS, ""));

				String ext = subInZip.substring(subInZip.lastIndexOf("."),
						subInZip.length());

				Path subfile = Paths.get(Regex.getEpisodeDest(ep).toString()
						+ "." + lang + ext);

				if (Files.exists(subfile)) {
					System.out.print(Constantes.DEBUGMSG
							.getString("searchFailed")
							+ Constantes.DEBUGMSG.getString("destSubExist"));
					SoutitreSet.remove(this);
					return;
				}

				// Téléchargement du ZIP
				Download.downloadfile(sub.getUrl(), zipfile.toString());

				// Système de fichiers ZIP
				FileSystem zipFS = FileSystems.newFileSystem(zipfile, null);

				// Copie de l'archive ZIP vers le disque dur
				Files.copy(zipFS.getPath(subInZip), subfile);

				if (Reglages.DEBUG)
					System.out.print(Constantes.DEBUGMSG
							.getString("searchComplete")
							+ String.format(
									Constantes.DEBUGMSG.getString("subAdded"),
									subfile.toString()));

				zipFS.close();

				// supression du zip téléchargé
				Files.delete(zipfile);

			}

			SoutitreSet.remove(this);

		} catch (Exception e) {
			SoutitreSet.add(this);
			new ProcessException(e);
		} finally {
			SoutitreSet.Save();
		}

	}

	public String getUrl() {
		return String.format("%s/s%02de%02d", url, season, episode);
	}

	public boolean equals(String url2, int se, int ep, SubtitleLanguage lang2) {
		if (url.equalsIgnoreCase(url2) && se == season && ep == episode
				&& lang == lang2)
			return true;
		return false;
	}

	public void move(Path file, Episode ep) throws IOException {

		String ext = file.toString().substring(
				file.toString().lastIndexOf("."), file.toString().length());

		Path subfile = Paths.get(Regex.getEpisodeDest(ep).toString() + "."
				+ lang + ext);

		if (Files.exists(subfile)) {
			Files.delete(subfile);
		}

		if (!Files.exists(subfile.getParent())) {
			Files.createDirectories(subfile.getParent());
		}

		Files.move(file, subfile);

		if (Reglages.DEBUG)
			System.out.print(String.format(
					Constantes.DEBUGMSG.getString("subAdded"),
					subfile.toString()));

	}

	public Object getNBTry() {
		return nbtry;
	}

}
